winsafe\gui\native_controls/
month_calendar.rs

1use std::any::Any;
2use std::marker::PhantomPinned;
3use std::pin::Pin;
4use std::sync::Arc;
5
6use crate::co;
7use crate::decl::*;
8use crate::gui::{events::*, privs::*, *};
9use crate::msg::*;
10use crate::prelude::*;
11
12struct MonthCalendarObj {
13	base: BaseCtrl,
14	events: MonthCalendarEvents,
15	_pin: PhantomPinned,
16}
17
18native_ctrl! { MonthCalendar: MonthCalendarObj => MonthCalendarEvents;
19	/// Native
20	/// [month calendar](https://learn.microsoft.com/en-us/windows/win32/controls/month-calendar-controls)
21	/// control.
22}
23
24impl MonthCalendar {
25	/// Instantiates a new `MonthCalendar` object, to be created on the parent
26	/// window with [`HWND::CreateWindowEx`](crate::HWND::CreateWindowEx).
27	///
28	/// # Panics
29	///
30	/// Panics if the parent window was already created – that is, you cannot
31	/// dynamically create a `MonthCalendar` in an event closure.
32	#[must_use]
33	pub fn new(parent: &(impl GuiParent + 'static), opts: MonthCalendarOpts) -> Self {
34		let ctrl_id = auto_id::set_if_zero(opts.ctrl_id);
35		let new_self = Self(Arc::pin(MonthCalendarObj {
36			base: BaseCtrl::new(ctrl_id),
37			events: MonthCalendarEvents::new(parent, ctrl_id),
38			_pin: PhantomPinned,
39		}));
40
41		let self2 = new_self.clone();
42		let parent2 = parent.clone();
43		parent
44			.as_ref()
45			.before_on()
46			.wm(parent.as_ref().wnd_ty().creation_msg(), move |_| {
47				self2.0.base.create_window(
48					opts.window_ex_style,
49					"SysMonthCal32",
50					None,
51					opts.window_style | opts.control_style.into(),
52					opts.position.into(),
53					SIZE::default(),
54					&parent2,
55				);
56				ui_font::set(self2.hwnd());
57
58				let mut bounds_rect = RECT::default();
59				unsafe {
60					self2
61						.hwnd()
62						.SendMessage(mcm::GetMinReqRect { bounds_rect: &mut bounds_rect })
63						.expect(DONTFAIL);
64				}
65				self2
66					.hwnd()
67					.SetWindowPos(
68						HwndPlace::None,
69						POINT::default(),
70						SIZE::with(bounds_rect.right, bounds_rect.bottom),
71						co::SWP::NOZORDER | co::SWP::NOMOVE,
72					)
73					.expect(DONTFAIL);
74
75				if opts.date.wDay != 0 {
76					self2.set_date(&opts.date)?;
77				}
78				parent2
79					.as_ref()
80					.add_to_layout(self2.hwnd(), opts.resize_behavior);
81				Ok(0) // ignored
82			});
83
84		new_self
85	}
86
87	/// Instantiates a new `MonthCalendar` object, to be loaded from a dialog
88	/// resource with [`HWND::GetDlgItem`](crate::HWND::GetDlgItem).
89	///
90	/// # Panics
91	///
92	/// Panics if the parent dialog was already created – that is, you cannot
93	/// dynamically create a `MonthCalendar` in an event closure.
94	#[must_use]
95	pub fn new_dlg(
96		parent: &(impl GuiParent + 'static),
97		ctrl_id: u16,
98		resize_behavior: (Horz, Vert),
99	) -> Self {
100		let new_self = Self(Arc::pin(MonthCalendarObj {
101			base: BaseCtrl::new(ctrl_id),
102			events: MonthCalendarEvents::new(parent, ctrl_id),
103			_pin: PhantomPinned,
104		}));
105
106		let self2 = new_self.clone();
107		let parent2 = parent.clone();
108		parent.as_ref().before_on().wm_init_dialog(move |_| {
109			self2.0.base.assign_dlg(&parent2);
110			parent2
111				.as_ref()
112				.add_to_layout(self2.hwnd(), resize_behavior);
113			Ok(true) // ignored
114		});
115
116		new_self
117	}
118
119	/// Retrieves the currently selected date by sending a
120	/// [`mcm::GetCurSel`](crate::msg::mcm::GetCurSel) message.
121	#[must_use]
122	pub fn date(&self) -> SysResult<SYSTEMTIME> {
123		let mut st = SYSTEMTIME::default();
124		unsafe {
125			self.hwnd().SendMessage(mcm::GetCurSel { info: &mut st })?;
126		}
127		Ok(st)
128	}
129
130	/// Sets the currently selected date by sending a
131	/// [`mcm::SetCurSel`](crate::msg::mcm::SetCurSel) message.
132	pub fn set_date(&self, st: &SYSTEMTIME) -> SysResult<()> {
133		unsafe { self.hwnd().SendMessage(mcm::SetCurSel { info: st }) }
134	}
135}
136
137/// Options to create a [`MonthCalendar`](crate::gui::MonthCalendar)
138/// programmatically with
139/// [`MonthCalendar::new`](crate::gui::MonthCalendar::new).
140pub struct MonthCalendarOpts {
141	/// Left and top position coordinates of control within parent's client
142	/// area, to be
143	/// [created](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowexw).
144	///
145	/// Defaults to `gui::dpi(0, 0)`.
146	pub position: (i32, i32),
147	/// Month calendar styles to be
148	/// [created](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowexw).
149	///
150	/// Defaults to `MCS::NoValue`.
151	pub control_style: co::MCS,
152	/// Window styles to be
153	/// [created](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowexw).
154	///
155	/// Defaults to `WS::CHILD | WS::GROUP | WS::TABSTOP | WS::VISIBLE`.
156	pub window_style: co::WS,
157	/// Extended window styles to be
158	/// [created](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowexw).
159	///
160	/// Defaults to `WS_EX::LEFT`.
161	pub window_ex_style: co::WS_EX,
162
163	/// The control ID.
164	///
165	/// Defaults to an auto-generated ID.
166	pub ctrl_id: u16,
167	/// Horizontal and vertical behavior of the control when the parent window
168	/// is resized.
169	///
170	/// **Note:** A `MonthCalendar` cannot be resized horizontally or
171	/// vertically, so it will panic if you use `Horz::Resize` or
172	/// `Vert::Resize`.
173	///
174	/// Defaults to `(gui::Horz::None, gui::Vert::None)`.
175	pub resize_behavior: (Horz, Vert),
176
177	/// Initial date.
178	///
179	/// Defaults to now.
180	pub date: SYSTEMTIME,
181}
182
183impl Default for MonthCalendarOpts {
184	fn default() -> Self {
185		Self {
186			position: dpi(0, 0),
187			control_style: co::MCS::NoValue,
188			window_style: co::WS::CHILD | co::WS::GROUP | co::WS::TABSTOP | co::WS::VISIBLE,
189			window_ex_style: co::WS_EX::LEFT,
190			ctrl_id: 0,
191			resize_behavior: (Horz::None, Vert::None),
192			date: SYSTEMTIME::default(),
193		}
194	}
195}